const axios = require('axios');
const { AppError } = require('../middlewares/errorHandler');
const WechatApp = require('../models/wechatApp');
const { logger } = require('../utils/logger');

class WechatService {
  constructor() {
    this.baseUrl = 'https://api.weixin.qq.com';
  }

  /**
   * 获取微信小程序配置
   * @param {string} appId - 小程序ID
   * @returns {Promise<Object>} - 小程序配置
   */
  async getWechatApp(appId) {
    const wechatApp = await WechatApp.scope('withSecrets').findOne({
      where: { appId }
    });

    if (!wechatApp) {
      throw new AppError(404, 'WeChat mini-program configuration not found');
    }
    return wechatApp;
  }

  /**
   * 刷新微信小程序access token
   * @param {string} appId - 小程序ID
   * @returns {Promise<string>} - access token
   */
  async refreshAccessToken(appId) {
    const wechatApp = await this.getWechatApp(appId);
    
    try {
      const response = await axios.get(`${this.baseUrl}/cgi-bin/token`, {
        params: {
          grant_type: 'client_credential',
          appid: wechatApp.appId,
          secret: wechatApp.appSecret
        }
      });

      if (response.data.errcode) {
        throw new AppError(400, `WeChat API Error: ${response.data.errmsg}`);
      }

      await wechatApp.update({
        accessToken: response.data.access_token,
        accessTokenExpiresAt: new Date(Date.now() + response.data.expires_in * 1000)
      });

      return wechatApp.accessToken;
    } catch (error) {
      logger.error('Error refreshing WeChat access token:', error);
      throw new AppError(500, 'Failed to refresh WeChat access token');
    }
  }

  /**
   * 获取微信小程序access token
   * @param {string} appId - 小程序ID
   * @returns {Promise<string>} - access token
   */
  async getAccessToken(appId) {
    const wechatApp = await this.getWechatApp(appId);
    
    if (!wechatApp.accessToken || !wechatApp.accessTokenExpiresAt || 
        wechatApp.accessTokenExpiresAt <= new Date()) {
      return this.refreshAccessToken(appId);
    }
    
    return wechatApp.accessToken;
  }

  /**
   * 获取微信小程序session key
   * @param {string} appId - 小程序ID
   * @param {string} code - 授权码
   * @returns {Promise<Object>} - session key
   */
  async code2Session(appId, code) {
    const wechatApp = await this.getWechatApp(appId);
    
    try {
      const response = await axios.get(`${this.baseUrl}/sns/jscode2session`, {
        params: {
          appid: wechatApp.appId,
          secret: wechatApp.appSecret,
          js_code: code,
          grant_type: 'authorization_code'
        }
      });

      if (response.data.errcode) {
        throw new AppError(400, `WeChat API Error: ${response.data.errmsg}`);
      }

      return {
        openid: response.data.openid,
        sessionKey: response.data.session_key,
        unionid: response.data.unionid
      };
    } catch (error) {
      logger.error('Error in code2Session:', error);
      throw new AppError(500, 'Failed to exchange code for session');
    }
  }

  /**
   * 生成微信小程序二维码
   * @param {string} appId - 小程序ID
   * @param {string} path - 路径
   * @param {Object} params - 参数
   * @returns {Promise<ArrayBuffer>} - 二维码
   */
  async generateQRCode(appId, path, params = {}) {
    const accessToken = await this.getAccessToken(appId);
    
    try {
      const response = await axios.post(
        `${this.baseUrl}/wxa/getwxacode?access_token=${accessToken}`,
        {
          path,
          width: params.width || 430,
          auto_color: params.autoColor || false,
          line_color: params.lineColor,
          is_hyaline: params.isHyaline || false
        },
        { responseType: 'arraybuffer' }
      );

      return response.data;
    } catch (error) {
      logger.error('Error generating QR code:', error);
      throw new AppError(500, 'Failed to generate QR code');
    }
  }

  /**
   * 发送模板消息
   * @param {string} appId - 小程序ID
   * @param {string} openId - 用户openId
   * @param {string} templateId - 模板ID
   * @param {Object} data - 数据
   * @param {string} page - 页面路径
   * @returns {Promise<Object>} - 发送结果
   */
  async sendTemplateMessage(appId, openId, templateId, data, page = '') {
    const accessToken = await this.getAccessToken(appId);
    
    try {
      const response = await axios.post(
        `${this.baseUrl}/cgi-bin/message/subscribe/send?access_token=${accessToken}`,
        {
          touser: openId,
          template_id: templateId,
          page,
          data
        }
      );

      if (response.data.errcode !== 0) {
        throw new AppError(400, `WeChat API Error: ${response.data.errmsg}`);
      }

      return response.data;
    } catch (error) {
      logger.error('Error sending template message:', error);
      throw new AppError(500, 'Failed to send template message');
    }
  }
}

module.exports = new WechatService(); 